/*
 * IBASIC - Interpretador BASIC para iniciantes
 * Autor original: prof. Cleuton Sampaio, Maio de 2003
 * Este programa é licenciado pela GPL e é Open Source
 */
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>
#include <sstream>
#include <jni.h>
#include <stdio.h>
#include <cctype>
#include "ibasic.h"

using namespace std;
/*
 * Argumentos:
 * ibasic [opcoes] <arquivo-fonte>.bas
 * opcoes:
 * -q : quieto, não mostre banners nem mensagens
 * -h : help
 */

// Flags de opções globais

bool opQ = false;
bool opH = false;
bool opL = false;
string fileName;
const string PRODUTO = "IBASIC - Interpretador Basic para iniciantes. (c) 2003 Cleuton Sampaio\nOpen Source - GNU GPL.";
const string VERSAO = "0.6 Beta (Ago, 2008)";
vector<string> programa;

stringstream touc;

// Funções

double analisarInfixa(string);
void analisarComando(int, char * []);
void mostrarBanner();
void carregarPrograma();
extern void executarPrograma(const vector<string> & prog, string & status);
void setMessages(bool);
void upper (char *);
string embedVersion (string);
void carregarDoString(string);

JNIEXPORT jstring JNICALL
Java_br_com_thecodebakers_ndk_Principal_embedVersion (JNIEnv *env, jobject obj, jstring progString) {

    char buf[10000];
    const char *str;
    str = env->GetStringUTFChars( progString, NULL);
    strcpy (buf, str);

    if (str == NULL) {
        return NULL; 
    }

    env->ReleaseStringUTFChars( progString, str);

	opL = true;
	mostrarBanner();
	carregarDoString(buf);

	string msg = "";
	//setMessages(!opQ);
	executarPrograma(programa, msg);
	if (msg.size() > 0) {
		if (!opQ) {
			touc << endl << msg;
		}
	}
	char * cstr;
	cstr = new char [touc.str().size()+1];
	strcpy (cstr, touc.str().c_str());
    return env->NewStringUTF(cstr);

	
}
/*
int main(int argc, char* argv[]) {
	analisarComando(argc, argv);
	mostrarBanner();
	carregarPrograma();
	string msg = "";
	//setMessages(!opQ);
	executarPrograma(programa, msg);
	if (msg.size() > 0) {
		if (!opQ) {
			touc << endl << msg;
		}
	}
}
*/
// Funções auxiliares

void carregarDoString(string progString) {

	const char * codigo = progString.c_str();
	char * linha = strtok((char*) codigo, "\n");
	while (linha != NULL) {
		upper(linha);
		programa.push_back(string(linha));
		linha = strtok(NULL, "\n");
	}
	if (opL) {
		int linha = 1;
		vector<string>::iterator it;
		for (it = programa.begin(); it < programa.end(); it++) {
			touc << endl << linha++ << " - " << *it;
		}
		touc << endl << endl << "----- Execucao -----" << endl;
	}
}

void analisarComando(int argc, char * argv[]) {
	for (int x = 0; x < argc; x++) {
		if (!strcmp(argv[x],"-q")) {
			opQ = true;
		}
		else {
			if (!strcmp(argv[x],"-h")) {
				opH = true;
			}
			else {
				if (!strcmp(argv[x],"-l")) {
					opL = true;
				}
				else {
					if ((x+1) == argc) {
						fileName = string(argv[x]);
					}
				}
			}
		}
	}
}

void mostrarBanner() {
	if (!opQ) {
		touc << endl << PRODUTO << " - VERSAO: " << VERSAO << endl;
		touc << "PROGRAMA: " << fileName << endl;
		if (opH) {
			touc << endl << "Uso: ibasic [opcoes] <arquivo-fonte>.bas"
					<< endl << "-q : quieto, nao mostre mensagens"
					<< endl << "-h : exibe texto de ajuda"
					<< endl << "-l : listar fonte";
		}
	}
}

void carregarPrograma() {
	fstream arquivo;
	char linha[1024];
	arquivo.open(fileName.c_str(), fstream::in);
	if (arquivo.fail()) {
		touc << endl << "******** ERRO AO ABRIR O ARQUIVO ***********";
		return;
	}

	while (!arquivo.eof()) {
		arquivo.getline(linha,1024);
		if (linha[0] == 0) {
			continue;
		}
		if (arquivo.fail()) {
			touc << endl << "******** ERRO DE LEITURA ***********";
			return;
		}
		upper(linha);
		programa.push_back(string(linha));
	}

	arquivo.close();

	if (opL) {
		int linha = 1;
		vector<string>::iterator it;
		for (it = programa.begin(); it < programa.end(); it++) {
			touc << endl << linha++ << " - " << *it;
		}
		touc << endl << endl << "----- Execucao -----" << endl;
	}
}

void upper(char * texto) {
	int tam = strlen(texto);
	for (int x = 0; x < tam; x++) {
		texto[x] = toupper(texto[x]);
	}
}
